前回の記事は「OpenCV + Pythonでの直線検出」を説明しました。今回はOpenCV + Pythonで図形を検出のことを説明します。
OpenCVのライブラリは領域(輪郭)の特徴のAPIがあります。領域(輪郭)の特徴である面積,周囲長,重心,外接矩形などの値を検出できます。
今回は面積(Contour area)、周囲長(arc length)、輪郭の近似(approxPolyDP)の関数で図形検出し、図形の数を数えます。
画像のオレンジの円形を検出します。
import cv2
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline
img = cv2.imread("orange.png")
plt.figure(figsize=(10, 10))
img2 = img[:,:,::-1]
plt.xticks([]), plt.yticks([])
plt.imshow(img2)
Pythonコード:
最初はファイルを読み込みで、グレースケール化します。そして、しきい値指定と輪郭を抽出します。最後は画像ファイルを作成します。
# ファイルを読み込み グレースケール化
img = cv2.imread("orange.png", cv2.IMREAD_GRAYSCALE)
# しきい値指定によるフィルタリング
_, threshold = cv2.threshold(img, 240, 255, cv2.THRESH_BINARY)
# 輪郭を抽出
_, contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
font = cv2.FONT_HERSHEY_DUPLEX
for cnt in contours:
approx = cv2.approxPolyDP(cnt, 0.01*cv2.arcLength(cnt, True), True)
cv2.drawContours(img, [approx], 0, (0), 2)
x = approx.ravel()[0]
y = approx.ravel()[1]
if len(approx) > 10:
cv2.putText(img, "circle", (x, y), font, 1, (0))
# 結果の画像作成
cv2.imwrite('output_circle.png',img)
結果の画像はの円の図形を検出し、領域輪郭を作成しました。
img = cv2.imread("output_circle.png")
plt.figure(figsize=(10, 10))
img2 = img[:,:,::-1]
plt.xticks([]), plt.yticks([])
plt.imshow(img2)
上記のスクリプトを参照し、図形を数えるコードを追加します。(### のコメント)
図形の数の変数作成し、画像に数を入れます。
Pythonコード:
import cv2
import numpy as np
# ファイルを読み込み グレースケール化
img = cv2.imread("orange.png", cv2.IMREAD_GRAYSCALE)
# しきい値指定によるフィルタリング
_, threshold = cv2.threshold(img, 240, 255, cv2.THRESH_BINARY)
# 輪郭を抽出
_, contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
font = cv2.FONT_HERSHEY_DUPLEX
### 図形の数の変数
circle = 0
for cnt in contours:
approx = cv2.approxPolyDP(cnt, 0.01*cv2.arcLength(cnt, True), True)
cv2.drawContours(img, [approx], 0, (0), 2)
x = approx.ravel()[0]
y = approx.ravel()[1]
if len(approx) > 10:
### 図形を数える
circle +=1
cv2.putText(img, "circle{}".format(circle), (x, y), font, 0.8, (0))
# 結果の画像作成
cv2.imwrite('output_count.png',img)
### 図形の数の結果
print('Number of circle = ' , circle)
結果の画像
各図形を検出し、下から数えました。
img = cv2.imread("output_count.png")
plt.figure(figsize=(10, 10))
img2 = img[:,:,::-1]
plt.xticks([]), plt.yticks([])
plt.imshow(img2)
下の画像から、円、楕円、三角形、四角形を数えます。図形検出のために、周囲長の数(v2.arcLength)です。
図形検出の設定
三角形 = 3、四角形 = 4、五角形 = 5、楕円形 > 6、<14、円形 > 16
img = cv2.imread("shapes.png")
plt.figure(figsize=(10, 10))
img2 = img[:,:,::-1]
plt.xticks([]), plt.yticks([])
plt.imshow(img2)
import cv2
import numpy as np
# ファイルを読み込み グレースケール化
img = cv2.imread("shapes.png", cv2.IMREAD_GRAYSCALE)
# しきい値指定によるフィルタリング
_, threshold = cv2.threshold(img, 240, 255, cv2.THRESH_BINARY)
# 輪郭を抽出
_, contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
font = cv2.FONT_HERSHEY_DUPLEX
# 図形の数の変数
triangle = 0
rectangle = 0
pentagon = 0
oval = 0
circle = 0
# 図形の設定
for cnt in contours:
approx = cv2.approxPolyDP(cnt, 0.01*cv2.arcLength(cnt, True), True)
cv2.drawContours(img, [approx], 0, (0), 2)
x = approx.ravel()[0]
y = approx.ravel()[1]
if len(approx) == 3:
triangle +=1
cv2.putText(img, "triangle{}".format(triangle), (x, y), font, 0.8, (0))
elif len(approx) == 4:
rectangle +=1
cv2.putText(img, "rectangle{}".format(rectangle), (x, y), font, 0.8, (0))
elif len(approx) == 5:
pentagon +=1
cv2.putText(img, "pentagon{}".format(pentagon), (x, y), font, 0.8, (0))
elif 6 < len(approx) < 14:
oval +=1
cv2.putText(img, "oval{}".format(oval), (x, y), font, 0.8, (0))
else:
circle +=1
cv2.putText(img, "circle{}".format(circle), (x, y), font, 0.8, (0))
# 結果の画像作成
cv2.imwrite('output_shapes.png',img)
# 図形の数の結果
print('Number of triangle = ' , triangle)
print('Number of rectangle = ' , rectangle)
print('Number of pentagon = ' , pentagon)
print('Number of circle = ' , circle)
print('Number of oval = ' , oval)
結果
OpendCVのライブラリで面積、周囲長、輪郭の近似を計算し、各図形を数えることができました。
img = cv2.imread("output_shapes.png")
plt.figure(figsize=(10, 10))
img2 = img[:,:,::-1]
plt.xticks([]), plt.yticks([])
plt.imshow(img2)